#include "rtthread.h"
#include "usart.h"
#include "gd32e10x.h"


#if defined(BSP_USING_UART0)
static void usart0_msp_init(void)
{
#if defined(USART0_TX_A9_RX_A10)
    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOA);
    /* connect port to USART0_Tx */
    gpio_init(GPIOA,GPIO_MODE_AF_PP,GPIO_OSPEED_MAX,GPIO_PIN_9);
    /* connect port to USART0_Rx */
    gpio_init(GPIOA,GPIO_MODE_IPU,GPIO_OSPEED_MAX,GPIO_PIN_10);
#elif defined(USART0_TX_B6_RX_B7)
    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_AF);
    rcu_periph_clock_enable(RCU_GPIOB);
    
    gpio_pin_remap_config(GPIO_USART0_REMAP,ENABLE);
    /* connect port to USART0_Tx */
    gpio_init(GPIOB,GPIO_MODE_AF_PP,GPIO_OSPEED_MAX,GPIO_PIN_6);
    /* connect port to USART0_Rx */
    gpio_init(GPIOB,GPIO_MODE_IPU,GPIO_OSPEED_MAX,GPIO_PIN_7);
#endif
}
#endif /* BSP_USING_UART0 */


#if defined(BSP_USING_UART1)
static void usart1_msp_init(void)
{
#if defined(USART1_TX_A2_RX_A3)
    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOA);
    /* connect port to USART1_Tx */
    gpio_init(GPIOA,GPIO_MODE_AF_PP,GPIO_OSPEED_MAX,GPIO_PIN_2);
    /* connect port to USART1_Rx */
    gpio_init(GPIOA,GPIO_MODE_IPU,GPIO_OSPEED_MAX,GPIO_PIN_3);
#elif defined(USART1_TX_D5_RX_D6)
    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_AF);
    rcu_periph_clock_enable(RCU_GPIOD);
    
    gpio_pin_remap_config(GPIO_USART1_REMAP,ENABLE);
    /* connect port to USART1_Tx */
    gpio_init(GPIOD,GPIO_MODE_AF_PP,GPIO_OSPEED_MAX,GPIO_PIN_5);
    /* connect port to USART1_Rx */
    gpio_init(GPIOD,GPIO_MODE_IPU,GPIO_OSPEED_MAX,GPIO_PIN_6);
#endif
}
#endif /* BSP_USING_UART1 */


#if defined(BSP_USING_UART2)
static void usart2_msp_init(void)
{
#if defined(USART2_TX_B10_RX_B11)
    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOB);
    /* connect port to USART2_Tx */
    gpio_init(GPIOB,GPIO_MODE_AF_PP,GPIO_OSPEED_MAX,GPIO_PIN_10);
    /* connect port to USART2_Rx */
    gpio_init(GPIOB,GPIO_MODE_IPU,GPIO_OSPEED_MAX,GPIO_PIN_11);
#elif defined(USART2_TX_C10_RX_C11)
    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_AF);
    rcu_periph_clock_enable(RCU_GPIOC);
    
    gpio_pin_remap_config(GPIO_USART2_PARTIAL_REMAP,ENABLE);
    /* connect port to USART2_Tx */
    gpio_init(GPIOC,GPIO_MODE_AF_PP,GPIO_OSPEED_MAX,GPIO_PIN_10);
    /* connect port to USART2_Rx */
    gpio_init(GPIOC,GPIO_MODE_IPU,GPIO_OSPEED_MAX,GPIO_PIN_11);
#elif defined(USART2_TX_D8_RX_D9)    
    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_AF);
    rcu_periph_clock_enable(RCU_GPIOD);
    
    gpio_pin_remap_config(GPIO_USART2_FULL_REMAP,ENABLE);
    /* connect port to USART2_Tx */
    gpio_init(GPIOD,GPIO_MODE_AF_PP,GPIO_OSPEED_MAX,GPIO_PIN_8);
    /* connect port to USART2_Rx */
    gpio_init(GPIOD,GPIO_MODE_IPU,GPIO_OSPEED_MAX,GPIO_PIN_9);
#endif
}
#endif /* BSP_USING_UART2 */


#if defined(BSP_USING_UART3)
static void uart3_msp_init(void)
{
#if defined(UART3_TX_C10_RX_C11)
    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOC);
    /* connect port to USART3_Tx */
    gpio_init(GPIOC,GPIO_MODE_AF_PP,GPIO_OSPEED_MAX,GPIO_PIN_10);
    /* connect port to USART3_Rx */
    gpio_init(GPIOC,GPIO_MODE_IPU,GPIO_OSPEED_MAX,GPIO_PIN_11);
#endif
}
#endif /* BSP_USING_UART3 */


#if defined(BSP_USING_UART4)
static void uart4_msp_init(void)
{
#if defined(UART4_TX_C12_RX_D2)
    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOC);
    rcu_periph_clock_enable(RCU_GPIOD);
    /* connect port to USART4_Tx */
    gpio_init(GPIOC,GPIO_MODE_AF_PP,GPIO_OSPEED_MAX,GPIO_PIN_12);
    /* connect port to USART4_Rx */
    gpio_init(GPIOD,GPIO_MODE_IPU,GPIO_OSPEED_MAX,GPIO_PIN_2);
#endif
}
#endif /* BSP_USING_UART4 */

static int uart_msp_init(uint32_t uart_periph)
{
    switch(uart_periph)
    {
#if defined(BSP_USING_UART0)        
        case USART0:
            usart0_msp_init();
            rcu_periph_clock_enable(RCU_USART0);            
            break;
#endif
        
#if defined(BSP_USING_UART1)
        case USART1:
            usart1_msp_init();
            rcu_periph_clock_enable(RCU_USART1);            
            break;
#endif
        
#if defined(BSP_USING_UART2)
        case USART2:
            usart2_msp_init();
            rcu_periph_clock_enable(RCU_USART2);             
            break; 
#endif
        
#if defined(BSP_USING_UART3)        
        case UART3:
            uart3_msp_init();
            rcu_periph_clock_enable(RCU_UART3);         
            break;
#endif
        
#if defined(BSP_USING_UART4)        
        case UART4:
            uart4_msp_init();
            rcu_periph_clock_enable(RCU_UART4);
            break;  
#endif        
        
        default:
            return RT_ERROR;
    }
    
    return RT_EOK;
}

int uart_init(uart_parameter_struct * uartx)
{
    int ret;
    RT_ASSERT( uartx->BaudRate > 0 );
    RT_ASSERT((uartx->HwFlowCtl == UART_HWCONTROL_NONE) || 
              (uartx->HwFlowCtl == UART_HWCONTROL_RTS)  ||
              (uartx->HwFlowCtl == UART_HWCONTROL_CTS)  ||
              (uartx->HwFlowCtl == UART_HWCONTROL_RTS_CTS) );
    RT_ASSERT((uartx->Mode == UART_MODE_RX) ||
              (uartx->Mode == UART_MODE_TX) ||
              (uartx->Mode == UART_MODE_TX_RX) );
    RT_ASSERT((uartx->Parity == USART_PM_NONE) || 
              (uartx->Parity == USART_PM_ODD)  || 
              (uartx->Parity == USART_PM_EVEN) );
    RT_ASSERT((uartx->periph == USART0) ||
              (uartx->periph == USART1) ||
              (uartx->periph == USART2) ||
              (uartx->periph == UART3)  ||
              (uartx->periph == UART4) );
    RT_ASSERT((uartx->StopBits == USART_STB_1BIT)   || 
              (uartx->StopBits == USART_STB_0_5BIT) || 
              (uartx->StopBits == USART_STB_2BIT)   || 
              (uartx->StopBits == USART_STB_1_5BIT) );
    RT_ASSERT((uartx->WordLength == USART_WL_8BIT) || 
              (uartx->WordLength == USART_WL_9BIT) );
              
    ret = uart_msp_init(uartx->periph);

    usart_deinit(uartx->periph);
    usart_baudrate_set(uartx->periph,uartx->BaudRate);
    usart_parity_config(uartx->periph,uartx->Parity);
    usart_word_length_set(uartx->periph,uartx->WordLength);
    usart_stop_bit_set(uartx->periph,uartx->StopBits);
    
    switch(uartx->Mode)
    {
    case UART_MODE_RX:
        usart_receive_config(uartx->periph, USART_RECEIVE_ENABLE);
        usart_transmit_config(uartx->periph, USART_TRANSMIT_DISABLE);
        break;
    
    case UART_MODE_TX:
        usart_receive_config(uartx->periph, USART_RECEIVE_DISABLE);
        usart_transmit_config(uartx->periph, USART_TRANSMIT_ENABLE);
        break;
    
    case UART_MODE_TX_RX:
        usart_receive_config(uartx->periph, USART_RECEIVE_ENABLE);
        usart_transmit_config(uartx->periph, USART_TRANSMIT_ENABLE);
        break;
    
    default:
        usart_receive_config(uartx->periph, USART_RECEIVE_ENABLE);
        usart_transmit_config(uartx->periph, USART_TRANSMIT_ENABLE);
        break;
    }

    switch(uartx->HwFlowCtl)
    {
    case UART_HWCONTROL_NONE:
        usart_hardware_flow_rts_config(uartx->periph,USART_RTS_DISABLE);
        usart_hardware_flow_cts_config(uartx->periph,USART_CTS_DISABLE);
        break;
    
    case UART_HWCONTROL_RTS:
        usart_hardware_flow_rts_config(uartx->periph,USART_RTS_ENABLE);
        usart_hardware_flow_cts_config(uartx->periph,USART_CTS_DISABLE);
        break;
    
    case UART_HWCONTROL_CTS:
        usart_hardware_flow_rts_config(uartx->periph,USART_RTS_DISABLE);
        usart_hardware_flow_cts_config(uartx->periph,USART_CTS_ENABLE);
        break;
    
    case UART_HWCONTROL_RTS_CTS:
        usart_hardware_flow_rts_config(uartx->periph,USART_RTS_ENABLE);
        usart_hardware_flow_cts_config(uartx->periph,USART_CTS_ENABLE);
        break;
    
    default:
        usart_hardware_flow_rts_config(uartx->periph,USART_RTS_DISABLE);
        usart_hardware_flow_cts_config(uartx->periph,USART_CTS_DISABLE);
        break;                       
    }
    
    usart_enable(uartx->periph);
    usart_flag_clear(uartx->periph,USART_FLAG_TC);   

    return ret;
}
